package com.shuaiche.yeguan.net.http;

import android.os.Environment;
import android.util.Log;

import com.shuaiche.yeguan.config.SCUserInfoConfig;
import com.shuaiche.yeguan.util.DeviceHelper;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.FileNameMap;
import java.net.Proxy;
import java.net.URLConnection;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.ConnectionPool;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;

/**
 * okhttp 网络请求实现类
 */
public class OkhttpRequest implements IHttpProcess {

    public static OkhttpRequest mInstance;
    private OkHttpClient okHttpClient;


    HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
        @Override
        public void log(String message) {
            Log.e("OkhttpRequest ", message);
        }
    });

    public OkhttpRequest() {
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
        okHttpClient = new OkHttpClient.Builder().connectionPool(new ConnectionPool())
                .proxy(Proxy.NO_PROXY)
                .sslSocketFactory(createSSLSocketFactory(), new TrustAllCerts())
                .hostnameVerifier(new TrustAllHostnameVerifier())
                .connectTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS).addInterceptor(logging).build();
    }

    public static OkhttpRequest getInstance() {
        if (mInstance == null) {
            synchronized (OkhttpRequest.class) {
                if (mInstance == null) {
                    mInstance = new OkhttpRequest();
                }
            }
        }
        return mInstance;
    }


    private  class TrustAllCerts implements X509TrustManager {
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
        public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];}
    }

    private  class TrustAllHostnameVerifier implements HostnameVerifier {
        public boolean verify(String hostname, SSLSession session) { return true; }
    }

    private  SSLSocketFactory createSSLSocketFactory() {
        SSLSocketFactory ssfFactory = null;
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());
            ssfFactory = sc.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ssfFactory;
    }

    public String getUrl(String urls, Map<String, Object> params) {
        String url = urls;
        if (params != null) {
            Iterator<Map.Entry<String, Object>> it = params.entrySet().iterator();
            StringBuffer sb = null;
            while (it.hasNext()) {
                Map.Entry<String, Object> entry = it.next();
                String key = entry.getKey();
                Object value = params.get(key);
                if (sb == null) {
                    sb = new StringBuffer();
                    sb.append("?");
                } else {
                    sb.append("&");
                }
                sb.append(key);
                sb.append("=");
                sb.append(String.valueOf(value));
            }
            url += sb.toString();

        }
        return url;
    }

    public void cancleAll(Object tag) {
        for (Call call : okHttpClient.dispatcher().queuedCalls()) {
            if (tag.equals(call.request().tag())) call.cancel();
        }

        for (Call call : okHttpClient.dispatcher().runningCalls()) {
            if (tag.equals(call.request().tag())) call.cancel();
        }
    }

    @Override
    public void post(String url, Map<String, Object> params, Object tag, Map<String, String> header, final CallBack callBack) {

        FormBody requestBody = null;
        FormBody.Builder builder = new FormBody.Builder();
        if (params != null) {
            Iterator<Map.Entry<String, Object>> it = params.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, Object> entry = it.next();
                String key = entry.getKey();
                Object value = params.get(key);
                builder.add(key, String.valueOf(value));
            }
        }
        requestBody = builder.build();
        Request.Builder requestBuilder = new Request.Builder();
        addHeaders(requestBuilder, header);
        if (tag != null) {
            requestBuilder.tag(tag);
        }
        Request request = requestBuilder
                .url(url)
                .post(requestBody)
                .build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callBack.onFinish();
                callBack.onFailure(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                callBack.onFinish();
                if (response.isSuccessful()) {
                    String result = response.body().string();
                    callBack.onSuccess(result);
                } else {
                    callBack.onFailure(null);
                }
            }
        });

    }

    @Override
    public void post(String url, String jsonStr, Object tag, Map<String, String> header, final CallBack callBack) {
        callBack.onStart();
        RequestBody body = RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), jsonStr);
        Request.Builder builder = new Request.Builder();
        addHeaders(builder, header);
        if (tag != null) {
            builder.tag(tag);
        }
        Request request = builder.url(url).post(body).build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callBack.onFinish();
                callBack.onFailure(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                callBack.onFinish();
                if (response.isSuccessful()) {
                    String result = response.body().string();
                    Headers requestHeaders= response.networkResponse().request().headers();
                    callBack.onSuccess(result);
                } else {
                    callBack.onFailure(null);
                }
            }
        });
    }

    @Override
    public void get(String url, Map<String, Object> params, Object tag, Map<String, String> header, final CallBack callback) {
        Request.Builder builder = new Request.Builder();
        addHeaders(builder, header);
        if (tag != null) {
            builder.tag(tag);
        }
        final Request request = builder
                .url(getUrl(url, params))
                .build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callback.onFinish();
                callback.onFailure(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                callback.onFinish();
                if (response.isSuccessful()) {
                    String result = response.body().string();
                    callback.onSuccess(result);
                } else {
                    callback.onFailure(null);
                }
            }
        });
    }

    @Override
    public void uploadFile(String url, Map<String, Object> params, Object tag, Map<String, String> header,
                           final CallBack callBack, File... files) {
        callBack.onStart();
        File[] filelist = files;
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        if (params != null) {
            Iterator<Map.Entry<String, Object>> it = params.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, Object> entry = it.next();
                String key = entry.getKey();
                Object value = params.get(key);
                builder.addFormDataPart(key, String.valueOf(value));
            }
        }

        for (int i = 0; i < filelist.length; i++) {
            File file = filelist[i];
            if (file != null && file.exists()) {
                RequestBody fileBody = RequestBody.create(MediaType.parse(guessMimeType(file.getName())), file);
                String key = "file";
                builder.addFormDataPart(key, file.getName(), fileBody);
            }

        }

        MultipartBody body = builder.build();
        Request.Builder requestBuilder = new Request.Builder();
        addHeaders(requestBuilder, header);
        if (tag != null) {
            requestBuilder.tag(tag);
        }
        Request request = requestBuilder.url(url).post(body).build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callBack.onFinish();
                callBack.onFailure(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                callBack.onFinish();
                if (response.isSuccessful()) {
                    String result = response.body().string();
                    callBack.onSuccess(result);
                } else {
                    callBack.onFailure(null);
                }
            }
        });
    }

    @Override
    public void downloadFile(final String url, final String savePath, final String fileName,
                             Object tag, Map<String, String> header, final DownloadListener listener,ProgressListener progressListener) {
        OkHttpClient client = okHttpClient.newBuilder().addNetworkInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Response response = chain.proceed(chain.request());
                return response.newBuilder().body(new ProgressResponseBody(response.body(),progressListener)).build();
            }
        }).build();
        Request.Builder builder = new Request.Builder();
        addHeaders(builder, header);
        if (tag != null) {
            builder.tag(tag);
        }
        final Request request = builder
                .url(url)
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                listener.onDownloadFailed();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;
                // 储存下载文件的目录
//                String saveFilePath = isExistDir(savePath);
                try {
                    is = response.body().byteStream();
                    long total = response.body().contentLength();
                    File file = new File(savePath, fileName);
                    fos = new FileOutputStream(file);
                    long sum = 0;
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                        sum += len;
//                        int progress = (int) (sum * 1.0f / total * 100);
//                        // 下载中
//                        listener.onDownloading(progress);
                    }
                    fos.flush();
                    // 下载完成
                    listener.onDownloadSuccess(savePath + fileName,total);
                } catch (Exception e) {
                    listener.onDownloadFailed();
                } finally {
                    try {
                        if (is != null)
                            is.close();
                    } catch (IOException e) {
                    }
                    try {
                        if (fos != null)
                            fos.close();
                    } catch (IOException e) {
                    }
                }
                if (response.isSuccessful()) {

                } else {
                    listener.onDownloadFailed();
                }

            }
        });
    }

    /**
     * 判断下载目录是否存在
     *
     * @param saveDir 保存路径
     * @return
     * @throws IOException
     */
    private String isExistDir(String saveDir)  {
        // 下载位置
        File downloadFile = new File(Environment.getExternalStorageDirectory()+File.separator+saveDir);
        if (!downloadFile.exists()) {
            downloadFile.mkdirs();

        }
        String savePath = downloadFile.getAbsolutePath();
        return savePath;
    }

    /**
     * 上传文件设置传输类型
     *
     * @param filename
     * @return
     */
    private String guessMimeType(String filename) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String contentTypeFor = fileNameMap.getContentTypeFor(filename);
        if (contentTypeFor == null) {
            contentTypeFor = "application/octet-stream";
        }
        return contentTypeFor;
    }

    /**
     * 添加请求头
     *
     * @param builder
     * @param header
     * @return
     */
    private Request.Builder addHeaders(Request.Builder builder, Map<String, String> header) {

        if (SCUserInfoConfig.isLogin() && SCUserInfoConfig.getUserinfo().getSessionId() != null) {
            builder.addHeader("user-session-id", SCUserInfoConfig.getUserinfo().getSessionId());
        }
        builder.addHeader("version", DeviceHelper.getAppVersion());
        builder.addHeader("source", "14");
        if (header != null) {
            Iterator<Map.Entry<String, String>> it = header.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, String> entry = it.next();
                String key = entry.getKey();
                String value = header.get(key);
                builder.addHeader(key, value);
            }
        }
        return builder;
    }
}
